/*
	Copyright (C) 2010 Salil Bhagurkar

	This file is part of k3

	k3 is free software: you can redistribute it and/or modify
	it under the terms of the GNU Lesser General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

	k3 is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU Lesser General Public License for more details.

	You should have received a copy of the GNU Lesser General Public License
	along with k3.  If not, see <http://www.gnu.org/licenses/>.
*/

#include <shared.h>

//Load modules from boot loader

extern void *multiboot_info;

#define FLAG_MODS (1<<3)

struct multiboot_info {
	u32 flags;
	u32 mem_lower;
	u32 mem_upper;
	u32 boot_device;
	u32 cmdline;
	u32 mods_count;
	u32 mods_addr;
	u32 syms[4];
	u32 mmap_length;
	u32 mmap_addr;
	u32 drives_length;
	u32 drives_addr;
	u32 config_table;
	u32 boot_loader_name;
	u32 apm_table;
	u32 vbe_control_info;
	u32 vbe_mode_info;
	u32 vbe_mode;
	u32 vbe_interface_set;
	u32 vbe_interface_off;
	u32 vbe_interface_len;
};

struct module {
	u32 mod_start;
	u32 mod_end;
	u32 string;
	u32 resvd;
};


/**
Procedure:
Get the modules count, to check for modules
Get the modules address
From the modules address, read an array of module structs specifying start and end of each module
Next, read the load address from the start address of each module
Relocate the module
From the load address, read the k3_module struct address as the second pointer from the start of the module (first being load address)
*/
int arch_init_modules()
{
	struct multiboot_info *m;
	struct module *mod;
	struct fs *k3_mod;
	struct fs *module_fs, *modules_fs;
	void *load_addr;
	u32 i;
	dprint(D_PROG, "modules", "Adding");
	modules_fs = fsparse_get("/modules");
	m = (struct multiboot_info *)multiboot_info;
	if(m->flags & FLAG_MODS) {
		printk(" %u\n", m->mods_count);
		for(i = 0, mod = (struct module *)m->mods_addr ; i < m->mods_count; i++, mod++) {
			load_addr = *((void **)mod->mod_start);
			memcpy(load_addr, (void *)mod->mod_start, mod->mod_end - mod->mod_start);
			k3_mod = *(struct fs **)(load_addr + sizeof(void *));
			printk("a>module %u ( %s )\n", i, k3_mod->name);
			fs_link(modules_fs, k3_mod);
		}
	}
	return 0;
}
